package com.cq.cqmall.search.thread;

import com.alibaba.nacos.shaded.com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.*;

/**
 * 线测试
 *
 * @author 程崎
 * @since 2022/10/24
 */
public class ThreadTest {

    /**
     * 自定义线程名称,方便的出错的时候溯源
     */
    private static final ThreadFactory NAMED_THREAD_FACTORY = new ThreadFactoryBuilder().setNameFormat("HISCADA-POOL-%d").build();

    /**
     * 工作顺序
     * 1、线程池创建，准备好corePoolSize数量的核心线程，准备接受任务
     * 1.1、corePoolSize满了之后，将新进入的任务放入阻塞队列中，空闲的核心线程会去阻塞队列获取任务执行
     * 1.2、阻塞队列满了之后，开启新线程运行，最大只能开到maximumPoolSize指定的数量
     * 1.3、maximumPoolSize满了则用RejectedExecutionHandler拒绝任务
     * 1.4、除核心线程外，其余线程在执行完毕过keepAliveTime时间后释放
     * new LinkedBlockingQueue<>()默认是Integer的最大值。可能内存不足
     * 面试题：
     * 一个线程池 core:7 max:20 queue:50, 100并发进来如何分配
     * 解答：
     * 1.7个线程池立即执行
     * 2.50个进入队列
     * 3.再开13个线程执行
     * 4.剩下30个使用拒绝策略执行
     * 5.如果不想抛弃可以使用CallerRunsPolicy
     */
    public static final ExecutorService SERVICE = new ThreadPoolExecutor(
            5,
            200,
            10,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100),
            NAMED_THREAD_FACTORY,
            new ThreadPoolExecutor.AbortPolicy()
    );

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start...");
        /*CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果：" + i);
        }, SERVICE);*/

        // 方法完成后的感知
        /*CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
                    System.out.println("当前线程：" + Thread.currentThread().getId());
                    int i = 10 / 0;
                    System.out.println("运行结果：" + i);
                    return i;
                }, SERVICE)
                .whenComplete((res, exception) -> System.out.println("异步任务完成！结果是：" + res + ";异常是：" + exception))
                .exceptionally(throwable -> 10);*/

        // 方法执行完毕后进行的处理
        /*CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果：" + i);
            return i;
        }, SERVICE).handle((res, thr) -> {
            if (res != null) {
                return res * 2;
            }
            if (thr != null) {
                return 0;
            }
            return -1;
        });*/

        /**
         * 线程串行化
         *  1、thenRun：不能获取到上一步的执行结果
         *  2、thenAccept：能接收上一步结果，但是无返回值
         *  3、thenApply：既能接收上一步结果，也有返回值
         */
        /*CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果：" + i);
            return i;
        }, SERVICE).thenApplyAsync(res -> {
            System.out.println("任务2启动，上一结果为：" + res);
            return "结果：" + res;
        }, SERVICE);;*/

        // 两个都完成
        /*CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程：" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1运行结果：" + i);
            return i;
        }, SERVICE);

        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程：" + Thread.currentThread().getId());
            System.out.println("任务2运行结束");
            return "Hello";
        }, SERVICE);

        *//*future01.runAfterBothAsync(future02, () -> {
            System.out.println("任务3开始");
        }, SERVICE);*//*
//        future01.thenAcceptBothAsync(future02, (f1, f2) -> System.out.println("任务3开始...之前的结果：" + f1 + "-->" + f2), SERVICE);
        CompletableFuture<String> future = future01.thenCombineAsync(future02, (t, u) -> t + "：" + u + "-> HaHa", SERVICE);*/

        /**
         * 两个任务，只要有一个完成，就执行任务3
         * runAfterEitherAsync：不感知结果，自己无返回值
         * acceptEitherAsync：感知结果，自己无返回值
         */
        /*CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程：" + Thread.currentThread().getId());
            int i = 10 / 4;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("任务1运行结果：" + i);
            return i;
        }, SERVICE);

        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程：" + Thread.currentThread().getId());
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("任务2运行结束");
            return "Hello";
        }, SERVICE);

//        future01.runAfterEitherAsync(future02, () -> System.out.println("任务3开始..."), SERVICE);
        *//*future01.acceptEitherAsync(future02, res -> {
            System.out.println("任务3开始，结果为：" + res);
        }, SERVICE);*//*
        CompletableFuture<String> future = future01.applyToEitherAsync(future02, res -> {
            System.out.println("任务3开始，结果为：" + res);
            return res.toString() + "->哈哈";
        }, SERVICE);*/

        CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品图片信息");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "Hello.jpg";
        },SERVICE);

        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品属性信息");
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "黑色+256G";
        },SERVICE);

        CompletableFuture<String> futureIntroduce = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品介绍");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "华为";
        },SERVICE);

//        CompletableFuture.allOf(futureImg, futureImg, futureIntroduce).join();
        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureImg, futureIntroduce);
        anyOf.join();

        System.out.println("main...end...结果：" + anyOf.get());
        System.out.println("main...end...结果：" + futureImg.get() + "=>" + futureAttr.get() + "=>" + futureIntroduce.get());

    }


    public void thread(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start...");
        /*Thread01 thread01 = new Thread01();
        thread01.start();
        new Thread(new Runnable01()).start();
        FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
        new Thread(futureTask).start();
        // 等待整个线程执行完成，获取返回结果
        Integer integer = futureTask.get();*/

        List<Integer> result = new LinkedList<>();
        for (int i = 0; i < 20; i++) {
            Future<Integer> submit = SERVICE.submit(new Callable01());
            result.add(submit.get());
        }

        System.out.println("main...end..." + result);
    }

    /**
     * 实现Callable
     *
     * @author 程崎
     * @since 2022/10/24
     */
    public static class Callable01 implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果：" + i);
            return i;
        }
    }

    /**
     * 继承thread
     *
     * @author 程崎
     * @since 2022/10/24
     */
    public static class Thread01 extends Thread {
        @Override
        public void start() {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果：" + i);
        }
    }

    /**
     * 实现Runnable
     *
     * @author 程崎
     * @since 2022/10/24
     */
    public static class Runnable01 implements Runnable {

        @Override
        public void run() {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果：" + i);
        }
    }
}
